package com.gph.saviorframework.wf.service.impl;

import com.gph.saviorframework.Constants;
import com.gph.saviorframework.wf.command.JumpTaskCmd;
import com.gph.saviorframework.wf.dao.CustomActivityTaskDao;
import com.gph.saviorframework.wf.service.*;
import com.gph.saviorframework.wf.utils.ListUtils;

import org.activiti.engine.HistoryService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.ExecutionImpl;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.DelegationState;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by root on 16-7-4.
 */
public class ActivitiTaskServiceImpl implements ActivitiTaskService {
	
    @Autowired
    private CustomActivityTaskDao customActivityTaskDao;
    
    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ActivitiDefService activitiDefService;

    @Autowired
    private ActivitiInsService activitiInsService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private ActivitiVarsService activitiVarsService;

    @Autowired
    private ActivitiFormService activitiFormService;

    /**
     * 根据流程实例编号获取当前执行任务
     *
     * @param processInsId
     * @return
     */
    public Task getCurrentTaskInfo(String processInsId) {
        Task currentTask = null;
        try{
            //执行实例
            ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery().
                    processInstanceId(processInsId).singleResult();
            //当前实例的执行到哪个节点
            String activitiId = execution.getActivityId();
            currentTask = taskService.createTaskQuery().processInstanceId(processInsId).taskDefinitionKey(activitiId)
                    .singleResult();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return currentTask;
    }
    
    @Override
	public List<Task> getCurrentTasks(String processInsId) {
    	List<Task> tasks = null;
    	try{
            //执行实例
            ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery().
                    processInstanceId(processInsId).singleResult();
            //当前实例的执行到哪个节点
            String activitiId = execution.getActivityId();
            tasks = taskService.createTaskQuery().processInstanceId(processInsId).taskDefinitionKey(activitiId).list();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    	return tasks;
	}

    /**
     * 根据流程实例获取当前执行任务
     *
     * @param processInstance
     * @return
     */
    public Task getCurrentTaskInfo(ProcessInstance processInstance) {
        Task currentTask = null;
        try {
            String activitiId = (String) PropertyUtils.getProperty(processInstance, "activityId");
            currentTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey(activitiId)
                    .singleResult();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return currentTask;
    }

    @Override
    public Task getTaskById(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    /**
     * 获取历史任务实例
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public HistoricTaskInstance findHistoricTaskInstance(String processInstanceId, String taskId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                .finished().taskId(taskId);
        return historicTaskInstanceQuery.singleResult();
    }

    /**
     * 获取已经审批的任务
     *
     * @param processDefinitionKey
     * @param userId
     * @return
     */
    public long countApprovedTasks(String processDefinitionKey, String userId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId)
                .processDefinitionKey(processDefinitionKey)
                .finished();
        return historicTaskInstanceQuery.count();
    }

    /**
     * 获取已经审批的任务
     *
     * @param processDefinitionKey
     * @param businessKey
     * @param userId               @return
     */
    @Override
    public long countApprovedTasks(String processDefinitionKey, String businessKey, String userId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId)
                .processDefinitionKey(processDefinitionKey)
                .processInstanceBusinessKey(businessKey)
                .finished();
        return historicTaskInstanceQuery.count();
    }

    /**
     * 获取已经完成的任务
     *
     * @param processDefinitionKey
     * @param userId
     * @param start
     * @param limit
     * @param sort
     * @param dir
     * @return
     */
    public List<HistoricTaskInstance> findApprovedTasks(String processDefinitionKey, String userId, Integer start, Integer limit, String sort, String dir) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId)
                .processDefinitionKey(processDefinitionKey)
                .finished()
                .orderByHistoricTaskInstanceStartTime()
                .orderByHistoricTaskInstanceEndTime();
        if(dir.toLowerCase().equals(Constants.DEFAULT_SORT_DIRECTION)) {
            historicTaskInstanceQuery = historicTaskInstanceQuery.asc();
        } else {
            historicTaskInstanceQuery = historicTaskInstanceQuery.desc();
        }
        if(start != null && limit != null) {
            return historicTaskInstanceQuery.listPage(start, limit);
        }
        return historicTaskInstanceQuery.list();
    }

    @Override
    public Map<String, Object> findApprovedTasksMap(String processDefinitionKey, String userId, Integer start, Integer limit, String sort, String dir) {
        Map<String,Object> map = new HashMap<String, Object>();

        List<HistoricTaskInstance> list = findApprovedTasks(processDefinitionKey, userId, start, limit, sort, dir);

        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        for(HistoricTaskInstance task : list) {
            Map<String, Object> temp = new HashMap<String, Object>();

            temp.put("taskName",task.getName());
            temp.put("taskAssignee",task.getAssignee());
            temp.put("taskId",task.getId());
            temp.put("taskStartTime",new DateConverter().convert(String.class, task.getStartTime()).toString());
            temp.put("taskEndTime",new DateConverter().convert(String.class, task.getEndTime()).toString());
            temp.put("businessKey",activitiInsService.findProcessInstance(task.getProcessInstanceId()).getBusinessKey());
            tasks.add(temp);
        }

        long records = countApprovedTasks(processDefinitionKey, userId);
        long total = 0;

        if(records%limit==0){
            total = records/limit;
        }
        else{
            total = records/limit + 1;
        }

        map.put(Constants.DEFAULT_RECORD_MODEL_KEY, tasks);
        map.put(Constants.DEFAULT_COUNT_MODEL_KEY, total);//总页数
        map.put(Constants.DEFAULT_RECORDS_MODEL_KEY,records);//总记录数目
        map.put(Constants.DEFAULT_SUCCESS_KEY, Boolean.TRUE);

        return map;
    }

    /**
     * 获取某个流程实例已经完成的任务
     *
     * @param processInstanceId
     * @return
     */
    public List<HistoricTaskInstance> findAllFinishedTasks(String processInstanceId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricTaskInstanceEndTime().desc();
        return historicTaskInstanceQuery.list();
    }

    /**
     * 完成任务
     *
     * @param taskId
     * @param userId
     * @param variables
     * @return
     */
    public boolean completeUserTask(String taskId, String userId, Map<String, Object> variables) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task != null && task.getAssignee().equals(userId)) {
            taskService.complete(taskId, variables);
            return true;
        }
        return false;
    }

    /**
     * 完成任务
     *
     * @param taskId
     * @param userId
     * @return
     */
    public boolean completeUserTask(String taskId, String userId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task != null && task.getAssignee().equals(userId)) {
            taskService.complete(taskId);
            return true;
        }
        return false;
    }

    /**
     * 接受任务
     *
     * @param taskId
     * @param userName
     * @return
     */
    public boolean claimTask(String taskId, String userName) {
        try {
            taskService.claim(taskId, userName);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 查找未完成的任务
     *
     * @param userId
     * @param start
     * @param limit
     * @param sort
     * @param dir
     * @return
     */
    public List<Task> findUnapprovedTasks(String userId, Integer start, Integer limit, String sort, String dir) {
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .active()
                .orderByTaskCreateTime();
        if(dir.toLowerCase().equals(Constants.DEFAULT_SORT_DIRECTION)) {
            taskQuery = taskQuery.asc();
        } else {
            taskQuery = taskQuery.desc();
        }
        if(start != null && limit != null) {
            return taskQuery.listPage(start, limit);
        }
        return taskQuery.list();
    }

    public List<Task> findUnapprovedTasks(String processDefKey, String userId, Integer start, Integer limit, String sort, String dir) {
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .processDefinitionKey(processDefKey)
                .active()
                .orderByTaskCreateTime();
        if(dir.toLowerCase().equals(Constants.DEFAULT_SORT_DIRECTION)) {
            taskQuery = taskQuery.asc();
        } else {
            taskQuery = taskQuery.desc();
        }
        if(start != null && limit != null) {
            return taskQuery.listPage(start, limit);
        }
        return taskQuery.list();
    }

    public Map<String, Object> findUnapprovedTasksMap(String processDefinitionKey, String userId, Integer start, Integer limit, String sort, String dir) {
        Map<String,Object> map = new HashMap<String, Object>();

        List<Task> list ;
        if(null!=processDefinitionKey)
        list= findUnapprovedTasks(processDefinitionKey,userId,start, limit, sort, dir);
        else
        list= findUnapprovedTasks(userId,start, limit, sort, dir);
        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        for(Task task : list) {
            Map<String, Object> temp = new HashMap<String, Object>();
            temp.put("id", task.getId());
            temp.put("taskName",task.getName());
            temp.put("taskKey",task.getTaskDefinitionKey());
            temp.put("taskAssignee",task.getAssignee());
            temp.put("processInstanceId",task.getProcessInstanceId());
            temp.put("processDefineId",task.getProcessDefinitionId());
            temp.put("createTime",task.getCreateTime());
            temp.put("formKey",activitiFormService.getFormKey(task.getId()));//外置表单的key
            //添加是否需要执行人走审批表单
            ProcessDefinitionEntity processDefinitionEntity = activitiDefService.
                    getProcessDefinitionEntity(task.getProcessDefinitionId());
            ActivityImpl activity = processDefinitionEntity.findActivity(task.getTaskDefinitionKey());
            String assignee = activitiDefService.getUserTaskAssignee(activity);
            if(assignee!=null && assignee.equals("${applyUserId}")){
                temp.put("needApprove",false);
            }
            else{
                temp.put("needApprove",true);
            }
            temp.put("businessKey",activitiInsService.findProcessInstance(task.getProcessInstanceId()).getBusinessKey());
            tasks.add(temp);
        }

        long records =0;
        if (null!=processDefinitionKey)
            records=countUnapprovedTasks(processDefinitionKey, userId);
        else
            records=countUnapprovedTasks(userId);
        long total = 0;

        if(records%limit==0){
            total = records/limit;
        }
        else{
            total = records/limit + 1;
        }

        map.put(Constants.DEFAULT_RECORD_MODEL_KEY, tasks);
        map.put(Constants.DEFAULT_COUNT_MODEL_KEY, total);//总页数
        map.put(Constants.DEFAULT_RECORDS_MODEL_KEY,records);//总记录数目
        map.put(Constants.DEFAULT_SUCCESS_KEY, Boolean.TRUE);

        return map;
    }

    /**
     * 计算某用户未完成的任务数量
     *
     * @param userId
     * @return
     */
    public long countUnapprovedTasks(String userId) {
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .active();
        return taskQuery.count();
    }

    public long countUnapprovedTasks(String processDefinitionKey, String userId) {
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .processDefinitionKey(processDefinitionKey)
                .active();
        return taskQuery.count();
    }

    /**
     * 根据流程实例编号获取最后一个执行任务
     *
     * @param processInsId
     * @return
     */
    public HistoricTaskInstance getLastTask(String processInsId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInsId)
                .orderByHistoricTaskInstanceStartTime()
                .desc().list().get(0);
    }

    @Override
    public void delegateTask(String taskId, String delegateUser) {
        taskService.delegateTask(taskId, delegateUser);
    }

    @Override
    public void resolveTask(String taskId) {
        taskService.resolveTask(taskId);
    }

    /**
     * 完成被委派的任务
     *
     * @param taskId
     * @param vars
     */
    @Override
    public void resolveTask(String taskId, Map<String, Object> vars) {
        taskService.resolveTask(taskId,vars);
    }

    @Override
    public List<Task> getDelegateTasksByUserId(String delegateUser) {
        return taskService.createTaskQuery().taskDelegationState(DelegationState.PENDING).taskAssignee(delegateUser).list();
    }

    /**
     * 发送消息事件
     * @param taskId
     * @param message
     */
    public void sendMessage(String taskId,String message){
        String processInstanceId=getTaskById(taskId).getProcessInstanceId();
        ExecutionQuery executionQuery = runtimeService.createExecutionQuery().messageEventSubscriptionName(message).processInstanceId(processInstanceId);
        Execution execution = executionQuery.singleResult();
        runtimeService.messageEventReceived(message, execution.getId());
    }

    /**
     * 自由流跳转
     *
     * @param targetTaskDefinitionKey 目标任务节点的流程定义key
     */
    @Override
    public void jump(String processInsId,String targetTaskDefinitionKey) {
        TaskEntity currentTask = (TaskEntity)getCurrentTaskInfo(processInsId);
        jump(currentTask, targetTaskDefinitionKey);
    }

    private void jump(final TaskEntity currentTask, String targetTaskDefinitionKey){
        final ActivityImpl activity = activitiDefService.findActivity(currentTask.getProcessDefinitionId(), targetTaskDefinitionKey);
        final ExecutionImpl execution = (ExecutionImpl)runtimeService.createExecutionQuery().executionId(currentTask.getExecutionId()).singleResult();
        ((RuntimeServiceImpl)runtimeService).getCommandExecutor().execute(new Command<Void>() {
            @Override
            public Void execute(CommandContext commandContext) {
                //创建新任务
                execution.setActivity(activity);
                execution.executeActivity(activity);

                //删除当前的任务
                //不能删除当前正在执行的任务，所以要先清除掉关联
                currentTask.setExecutionId(null);
                taskService.saveTask(currentTask);
                taskService.deleteTask(currentTask.getId(), true);
                return null;
            }
        });
    }

    /**
     * 获取业务key集合
     *
     * @param processDefinitionKey
     * @param userId
     * @param dir
     * @return
     */
    @Override
    public List<String> getBusinessKeys(String processDefinitionKey, String userId, String dir) {
        List<HistoricTaskInstance> historicTaskInstances = findApprovedTasks(processDefinitionKey, userId, null, null, null, dir);

        List<String> keys = new ArrayList<>();
        String key  = null;
        for(HistoricTaskInstance task : historicTaskInstances) {
            key = activitiInsService.findProcessInstance(task.getProcessInstanceId()).getBusinessKey();
            if(!keys.contains(key)){
                keys.add(key);
            }
        }
        return keys;
    }

    public Map<String,Object> getBusinessKeysMap(String processDefinitionKey, String userId, int start,int limit,String dir) {
        Map<String,Object> map = new HashMap<String, Object>();

        List<String> keys = getBusinessKeys(processDefinitionKey,userId,dir);

        long records = keys.size();
        long total = 0;

        if(records%limit==0){
            total = records/limit;
        }
        else{
            total = records/limit + 1;
        }

        map.put(Constants.DEFAULT_RECORD_MODEL_KEY, ListUtils.splitList(keys,start,limit));
        map.put(Constants.DEFAULT_COUNT_MODEL_KEY, total);//总页数
        map.put(Constants.DEFAULT_RECORDS_MODEL_KEY,records);//总记录数目
        map.put(Constants.DEFAULT_SUCCESS_KEY, Boolean.TRUE);

        return map;
    }

    /**
     * 计算已经完成任务的业务key
     *
     * @param processDefinitionKey
     * @param userId
     * @return
     */
    @Override
    public long countBusinessKeys(String processDefinitionKey, String userId) {
        return getBusinessKeys(processDefinitionKey,userId,Constants.DEFAULT_SORT_DIRECTION).size();
    }
    @Override
    public List<Map<String,String>> appGetTaskCount(String username){
        return customActivityTaskDao.unApproveTaskCount(username);
    }

    /**
     * 任务跳转
     *
     * @param processInsId
     * @param destTaskDefId
     */
    @Override
    public void jump2(String processInsId, String destTaskDefId) {
        final TaskEntity currentTask = (TaskEntity)getCurrentTaskInfo(processInsId);
        ReadOnlyProcessDefinition processDefinition = activitiDefService.getProcessDefinitionEntity(currentTask.getProcessDefinitionId());

        final ActivityImpl destinationActivity = (ActivityImpl) processDefinition.findActivity(destTaskDefId);
        ActivityImpl currentActivity = (ActivityImpl) processDefinition.findActivity(currentTask.getTaskDefinitionKey());

        managementService.executeCommand(new JumpTaskCmd(currentTask.getExecutionId(),
                destinationActivity, activitiVarsService.getAllVars(currentTask.getExecutionId()), currentActivity));
    }
}
